//---------------------------------------------------------------------------
#include <String.h>
#include <StdIO.h>

#include "PC2CM5.h"

//---------------------------------------------------------------------------
//  This module uses ints where bools should be used as the Atmel compiler
//  doesn't support bools.
//---------------------------------------------------------------------------

int StringIsCompletePacket(char *Packet)
{
    int         RetVal = 0;

    if (strlen(Packet) == PACKET_LEN)
        if ( (Packet[0] == '[') && (Packet[PACKET_LEN-1] == ']') )
            RetVal = 1;

    return RetVal;
}
//---------------------------------------------------------------------------

int CheckPacket(char *Packet)
{

    int RetVal = StringIsCompletePacket(Packet);

    if (RetVal)
        RetVal = CheckPacketCRC(Packet);

    return RetVal;


}
//---------------------------------------------------------------------------

int CheckPacketCRC(char *Packet)
{
    int CRC = (crc_compute(Packet+1, PACKET_LEN-6) & 0xFFFF);    //  -6 for CRC & end delimiter
    return (HexCharsToInt(Packet+PACKET_LEN-5, 4) == CRC)? 1: 0;
}
//---------------------------------------------------------------------------

void MakePacket1(char *Packet, char Command, char *Data)
    //  Data must contain 12 characters.  NULL is optional
{
    Packet[0] = '[';
    Packet[1] = Command;
    memcpy(Packet+2, Data, 12);
    int CRC = (crc_compute(Packet+1, PACKET_LEN-6) & 0xFFFF);    //  -6 for CRC & end delimiter
    IntToHexChars(CRC, Packet+14, 4);
    memcpy(Packet+18, "]", 2);
}
//---------------------------------------------------------------------------

void MakePacket2(char *Packet, char Command, int i1, int i2, int i3)
{
    char    Buff1[20];
    IntToHexChars(i1, &Buff1[0], 4);
    IntToHexChars(i2, &Buff1[4], 4);
    IntToHexChars(i3, &Buff1[8], 4);
    MakePacket1(Packet, Command, Buff1);
}
//---------------------------------------------------------------------------

void SplitPacket1(char *Packet, char *Data)
    //  Data will be 12 chars followed by a NULL
{
    memcpy(Data, Packet+2, 12);
    Data[12] = '\0';
}
//---------------------------------------------------------------------------

void SplitPacket2(char *Packet, int *i1, int *i2, int *i3)
{
    *i1 = HexCharsToInt(Packet+2,  4);
    *i2 = HexCharsToInt(Packet+6,  4);
    *i3 = HexCharsToInt(Packet+10, 4);
}
//---------------------------------------------------------------------------

int  HexCharToInt(char c)
    //  Pass in e.g. '3' or 'c' or 'C' & get back e.g. 0x3 or 0xC
{
    int RetVal = 0;

    if ( (c >= '0') && (c <= '9') )
        RetVal = c - '0';

    else if ( (c >= 'a') && (c <= 'f') )
        RetVal = c - 'a' + 10;

    else if ( (c >= 'A') && (c <= 'F') )
        RetVal = c - 'A' + 10;

    return RetVal;
}
//---------------------------------------------------------------------------

int  HexCharsToInt(char *c, int CharsToConvert)
    //  e.g. HexCharsToInt("04fC", 4) returns 0x4FC.  CharsToConvert will normally be 2 or 4
{
    int         RetVal = 0,
                Negative,
                SubVal = 0;

    Negative = HexCharToInt(*c) & 0x8;

    while(1)
    {
        RetVal += HexCharToInt(*c++);
        SubVal |= 0xF;

        if (--CharsToConvert > 0)
        {
            RetVal <<= 4;
            SubVal <<= 4;
        }
        else
            break;
    }

    if (Negative)
        RetVal = (SubVal - RetVal + 1) * -1;

    return RetVal;
}
//---------------------------------------------------------------------------

void IntToHexChars(int Val, char *String, int ConvChars)
    //  e.g. IntToHexChars(0x12b, String, 4) yields String = "012B"
{
    int         i;
    char        Digits[] = "0123456789ABCDEF";

    i = (ConvChars == 4)? 3: 1;
    String[i+1] = '\0';
    for (; i >= 0; i --, Val >>= 4) //  Converts 4 chars to start with
        String[i] = Digits[Val & 0xF];
}
//---------------------------------------------------------------------------

int crc_compute(char *buf, int size)
{
   int index, crc;
   int v, xor_flag, byte, bit;

   crc = INITIAL_VALUE;

   for(index = 0; index < size; index++) {
      byte = buf[index];
      /*
	Align test bit with leftmost bit of the message byte.
      */
      v = 0x80;

      for(bit = 0; bit < 8; bit++) {
	 if(crc & 0x8000)
            xor_flag= 1;
	 else
            xor_flag= 0;

	 crc = crc << 1;

	 /*  Append next bit of message to end of CRC if it is not zero.
	     The zero bit placed there by the shift above need not be
	     changed if the next bit of the message is zero. */
	 if(byte & v)
	    crc= crc + 1;

	 if(xor_flag)
	    crc = crc ^ POLY;

	 /* Align test bit with next bit of the message byte. */
	 v = v >> 1;
      }
   }

   /* We have to augment the crc in order to comply with the ccitt spec. */

    for(bit = 0; bit < 16; bit++) {
        if(crc & 0x8000)
            xor_flag= 1;
        else
            xor_flag= 0;

	crc = crc << 1;

        if(xor_flag)
            crc = crc ^ POLY;
    }

    return crc;
}
//---------------------------------------------------------------------------

